﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Runtime.InteropServices;
using System.Security;
using System.Net;
using System.ServiceProcess;
using System.Net.Sockets;

namespace UselessExplorer.UI
{
    public partial class ucNetworkStatus : UserControl
    {
        private string m_InvalidIP = String.Empty;

        public ucNetworkStatus ()
        {
            InitializeComponent();
            m_InvalidIP = UselessExplorer.Properties.UselessResources.ucNetworkUnknowHost;
        }

        private void ucNetworkStatus_Load ( object sender, EventArgs e )
        {
            StartScan();
        }

        private void StartScan ()
        {
            if (!bwNetworkStatus.IsBusy)
            {
                bwNetworkStatus.RunWorkerAsync();
            }
        }

        private List<IPAddress> GetIPAddress ( string HostName )
        {
            try
            {
                List<IPAddress> IpList = new List<IPAddress>();
                
                IPAddress[] addresslist = Dns.GetHostAddresses( HostName );

                foreach(IPAddress theaddress in addresslist)
                {
                    IpList.Add( theaddress );
                }

                return IpList;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        
        //declare the Netapi32 : NetServerEnum method import
        [DllImport( "Netapi32", CharSet = CharSet.Auto, SetLastError = true ), SuppressUnmanagedCodeSecurityAttribute]

        /// <summary>
        /// Netapi32.dll : The NetServerEnum function lists all servers
        /// of the specified type that are visible in a domain. For example, an 
        /// application can call NetServerEnum to list all domain controllers only
        /// or all SQL servers only. You can combine bit masks to list
        /// several types. For example, a value of 0x00000003  combines the bit
        /// masks for SV_TYPE_WORKSTATION (0x00000001) and SV_TYPE_SERVER (0x00000002)
        /// </summary>
        public static extern int NetServerEnum (
            string ServerNane, // must be null
            int dwLevel,
            ref IntPtr pBuf,
            int dwPrefMaxLen,
            out int dwEntriesRead,
            out int dwTotalEntries,
            int dwServerType,
            string domain, // null for login domain
            out int dwResumeHandle
            );

        //declare the Netapi32 : NetApiBufferFree method import
        [DllImport( "Netapi32", SetLastError = true ), SuppressUnmanagedCodeSecurityAttribute]

        /// <summary>
        /// Netapi32.dll : The NetApiBufferFree function frees 
        /// the memory that the NetApiBufferAllocate function allocates. 
        /// Call NetApiBufferFree to free the memory that other network 
        /// management functions return.
        /// </summary>
        public static extern int NetApiBufferFree ( IntPtr pBuf );

        //create a _SERVER_INFO_100 STRUCTURE

        [StructLayout( LayoutKind.Sequential )]
        public struct _SERVER_INFO_100
        {
            internal int sv100_platform_id;
            [MarshalAs( UnmanagedType.LPWStr )]
            internal string sv100_name;
        }

        /// <summary>
        /// Uses the DllImport : NetServerEnum
        /// with all its required parameters
        /// (see http://msdn.microsoft.com/library/default.asp?  url=/library/en-us/netmgmt/netmgmt/netserverenum.asp
        /// for full details or method signature) to
        /// retrieve a list of domain SV_TYPE_WORKSTATION
        /// and SV_TYPE_SERVER PC's
        /// </summary>
        /// <returns>Arraylist that represents
        /// all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER
        /// PC's in the Domain
        /// </returns>
        public ArrayList GetNetworkComputers ()
        {
            //local fields

            ArrayList networkComputers = new ArrayList();
            const int MAX_PREFERRED_LENGTH = -1;
            int SV_TYPE_WORKSTATION = 1;
            int SV_TYPE_SERVER = 2;
            IntPtr buffer = IntPtr.Zero;
            IntPtr tmpBuffer = IntPtr.Zero;
            int entriesRead = 0;
            int totalEntries = 0;
            int resHandle = 0;
            int sizeofINFO = Marshal.SizeOf( typeof( _SERVER_INFO_100 ) );


            try
            {
                //call the DllImport : NetServerEnum 
                //with all its required parameters
                //see http://msdn.microsoft.com/library/
                //default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp
                //for full details of method signature

                int ret = NetServerEnum( null, 100, ref buffer,
                    MAX_PREFERRED_LENGTH,
                    out entriesRead,
                    out totalEntries, SV_TYPE_WORKSTATION |
                    SV_TYPE_SERVER, null, out 
                    resHandle );
                //if the returned with a NERR_Success 

                //(C++ term), =0 for C#

                if (ret == 0)
                {
                    //loop through all SV_TYPE_WORKSTATION 

                    //and SV_TYPE_SERVER PC's

                    for (int i = 0; i < totalEntries; i++)
                    {
                        //get pointer to, Pointer to the 
                        //buffer that received the data from the call to NetServerEnum. 
                        //Must ensure to use correct size of STRUCTURE to ensure correct 
                        //location in memory is pointed to
                        tmpBuffer = new IntPtr( (int)buffer + (i * sizeofINFO) );

                        //Have now got a pointer to the list 
                        //of SV_TYPE_WORKSTATION and 
                        //SV_TYPE_SERVER PC's, which is unmanaged memory
                        //Needs to Marshal data from an 
                        //unmanaged block of memory to a 
                        //managed object, again using 
                        //STRUCTURE to ensure the correct data
                        //is marshalled 
                        _SERVER_INFO_100 svrInfo = (_SERVER_INFO_100)Marshal.PtrToStructure( tmpBuffer, typeof( _SERVER_INFO_100 ) );

                        //add the PC names to the ArrayList
                        networkComputers.Add( svrInfo.sv100_name );
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show( "Problem with acessing " + "network computers in NetworkBrowser " + "\r\n\r\n\r\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error );
                return null;
            }
            finally
            {
                //The NetApiBufferFree function frees the memory that the 
                //NetApiBufferAllocate function allocates
                NetApiBufferFree( buffer );
            }
            //return entries found
            return networkComputers;
        }

        private void bwNetworkStatus_DoWork ( object sender, DoWorkEventArgs e )
        {
            ArrayList al = new ArrayList();
            al = GetNetworkComputers();

            TcpClient TcpScan = new TcpClient();
            DataTable dt = new DataTable();
            dt.Columns.Add( new DataColumn( "Host Name" ) );
            dt.Columns.Add( new DataColumn( "IP Address" ) );
            dt.Columns.Add( new DataColumn( "HTTP Server" ) );

            
            for (int index = 0; index < al.Count; index++)
            {
                List<IPAddress> ip = GetIPAddress( al[index].ToString() );
                
                int percentage = (int)(index * 100) / al.Count;

                bwNetworkStatus.ReportProgress( percentage );

                DataRow dr = dt.NewRow();
                dr[0] = al[index];
                dr[1] = ParseIPListToString( ip );

                if (!ip.Equals( m_InvalidIP ))
                    dr[2] = CheckHttpPorts( ip );
                
                dt.Rows.Add( dr );
            }
            
            e.Result = dt;
        }

        private string ParseIPListToString ( List<IPAddress> ip )
        {
            int count = 1;
            string ips = string.Empty;

            foreach (IPAddress i in ip)
            {
                ips += i.ToString();

                if ( count < ip.Count)
                    ips += " , ";

                count++;
            }
            return ips;
        }

        private void bwNetworkStatus_ProgressChanged ( object sender, ProgressChangedEventArgs e )
        {
            ProgressBar.Value = e.ProgressPercentage;
        }

        private void bwNetworkStatus_RunWorkerCompleted ( object sender, RunWorkerCompletedEventArgs e )
        {
            dgNetworkStatusList.DataSource = (DataTable)e.Result;
            lblScanning.Text = UselessExplorer.Properties.UselessResources.ucNetworkScanning;
            ProgressBar.Value = 0;
        }

       

        private string CheckHttpPorts ( List<IPAddress> ip )
        {
            int count = 1;
            string _http_active = string.Empty;

            TcpClient TcpScan = new TcpClient();
            ArrayList HttpPorts = new ArrayList();
            HttpPorts.Add( 80 );
            HttpPorts.Add( 8080 );

            Socket connector = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );

            foreach (IPAddress i in ip)
            {
                _http_active += "(";

                foreach (int Port in HttpPorts)
                {
                    Socket conector = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
                    IPAddress ipAddress = new IPAddress( IPAddressToLong( i.ToString() ) );
                    EndPoint ep = new IPEndPoint( ipAddress, Port );

                    try
                    {
                        conector.Connect( ep );
                        _http_active += String.Format("{0} - Active",Port);
                    }
                    catch
                    {
                        _http_active += String.Format( "{0} - Inactive", Port );
                    }

                    if (count < HttpPorts.Count)
                        _http_active += " , ";

                    count++;
                }

                _http_active += ")";
                count = 1;
            }
            return _http_active;
        }



        static public uint IPAddressToLong ( string IPAddr )
        {
            System.Net.IPAddress oIP = System.Net.IPAddress.Parse( IPAddr );
            byte[] byteIP = oIP.GetAddressBytes();


            uint ip = (uint)byteIP[3] << 24;
            ip += (uint)byteIP[2] << 16;
            ip += (uint)byteIP[1] << 8;
            ip += (uint)byteIP[0];

            return ip;
        }

        public void StartScanOnTabClick ()
        {
            StartScan();
        }

    }
}



